package code.network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

import code.wrtp.Constants;
import code.wrtp.Receiver;

public class PacketRx implements Runnable {

	private PacketBroadcastRx packetBroadcastRx;
	private DatagramSocket datagramSocket;
	private volatile boolean isRunning;
	/* For passing received message to the up layer */
	private Receiver receiver;
	private Thread threadPacketRx;
	private AddressUtil addressUtil;

	public PacketRx(Receiver receiver, String subNet, short address, short port) {
		try {
			this.receiver = receiver;
			addressUtil = receiver.getAddressUtil();
			datagramSocket = new DatagramSocket(new InetSocketAddress(
					addressUtil.makeAddressForInet(address, subNet), port));
			datagramSocket.setBroadcast(true);
			packetBroadcastRx = new PacketBroadcastRx(port);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void startThread() {
		isRunning = true;
		packetBroadcastRx.startBroadcastReceive();
		threadPacketRx = new Thread(this);
		threadPacketRx.start();
	}

	public void stopThread() {
		isRunning = false;
		packetBroadcastRx.stopBroadcastReceive();
		threadPacketRx.interrupt();
	}

	@Override
	public void run() {
		while (isRunning) {

			byte[] buffer = new byte[64000];
			DatagramPacket packetReceiver = new DatagramPacket(buffer,
					buffer.length);
			try {
				datagramSocket.receive(packetReceiver);

				int contentLength = packetReceiver.getLength();
				byte[] content = new byte[contentLength];
				System.arraycopy(packetReceiver.getData(), 0, content, 0,
						contentLength);

				short destineIP = addressUtil
						.getAddressFromDatagramPacket(packetReceiver
								.getAddress().toString());
				if (destineIP == receiver.getStation().getNode().getNodeID()) {
					receiver.keepReceivedMessage(destineIP, content);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	private class PacketBroadcastRx implements Runnable {

		private volatile boolean isBroadcasting;
		private DatagramSocket broadcastDatagramSocket;
		private Thread threadPacketBroadcastRx;

		public PacketBroadcastRx(short receiverPort) {
			try {
				broadcastDatagramSocket = new DatagramSocket(receiverPort + 1);
			} catch (SocketException e) {
				e.printStackTrace();
			}
		}

		public void startBroadcastReceive() {
			isBroadcasting = true;
			threadPacketBroadcastRx = new Thread(this);
			threadPacketBroadcastRx.start();
		}

		public void stopBroadcastReceive() {
			isBroadcasting = false;
			threadPacketBroadcastRx.interrupt();
		}

		@Override
		public void run() {

			while (isBroadcasting) {

				byte[] buffer = new byte[64000];
				DatagramPacket bcReceivePacket = new DatagramPacket(buffer,
						buffer.length);

				try {
					broadcastDatagramSocket.receive(bcReceivePacket);
					int packetContentLength = bcReceivePacket.getLength();
					byte[] content = new byte[packetContentLength];

					System.arraycopy(bcReceivePacket.getData(), 0, content, 0,
							packetContentLength);

					/* WORK ON CONTENT ARRAY */
					short destineIP = addressUtil
							.getAddressFromDatagramPacket(bcReceivePacket
									.getAddress().toString());
					if (destineIP == Constants.BROADCAST_ADDRESS) {
						receiver.keepReceivedMessage(destineIP, content);
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
